package com.zx.flow.api.execute.request.valid;

import jakarta.validation.Constraint;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import jakarta.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Objects;
import org.springframework.util.StringUtils;

/**
 * 自定义，使用spring 校验的时候，增强枚举值的校验
 *
 * @author zhangxue
 */
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EnumValidator.Validator.class)
public @interface EnumValidator {

    String message() default " 枚举值不存在";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    Class<? extends Enum<?>> enumClass();

    String enumMethod() default "valueOf";

    public static class Validator implements ConstraintValidator<EnumValidator, Object> {

        private EnumValidator enumValidator;

        @Override
        public void initialize(EnumValidator EnumValidator) {
            this.enumValidator = EnumValidator;
        }

        @Override
        public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
            String enumMethod = this.enumValidator.enumMethod();
            Class<? extends Enum<?>> enumClass = this.enumValidator.enumClass();
            if (value == null) {
                return Boolean.TRUE;
            }

            if (enumClass == null || enumMethod == null) {
                return Boolean.TRUE;
            }

            // 默认的valueOf方法，获得枚举值，获得不到则抛出异常
            if ("valueOf".equals(enumMethod)) {
                try {
                    Method method = enumClass.getMethod(enumMethod, String.class);
                    method.invoke(null, value);
                    return true;
                } catch (Exception e) {
                    return false;
                }
            }
            Class<?> valueClass = value.getClass();
            // 使用自定义的方法，校验枚举。
            // ps:方法在定义在枚举中，参数只有一个值，返回值Boolean类型
            try {
                Method method = enumClass.getMethod(enumMethod, valueClass);
                // 比较的方法。不能返回void
                if (Objects.equals(method.getReturnType(), Void.class)) {
                    throw new RuntimeException(
                            String.format("%s method return type is void in the %s class", enumMethod, enumClass));
                }
                // 只允许静态方法
                if (!Modifier.isStatic(method.getModifiers())) {
                    throw new RuntimeException(
                            String.format("%s method is not static method in the %s class", enumMethod, enumClass));
                }

                // 没有返回值，直接返回失败
                Object result = method.invoke(null, value);
                if (result == null) {
                    return false;
                }

                if (result instanceof String) {
                    return !StringUtils.isEmpty((String) result);
                } else if (result instanceof Boolean || Objects.equals(result.getClass(), boolean.class)) {
                    return (boolean) result;
                }
                return result != null;
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                throw new RuntimeException(e);
            } catch (NoSuchMethodException | SecurityException e) {
                throw new RuntimeException(
                        String.format("This %s(%s) method does not exist in the %s", enumMethod, valueClass, enumClass),
                        e);
            }
        }
    }

}